package com.gframework.core.middleware;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.http.client.CookieStore;
import org.apache.http.cookie.Cookie;

/**
 * 这是一个线程安全且线程互相不共享的，可设置是否进行cookie缓存的CookieStore对象.
 * <p>同时需要特别注意的是，本类是全局唯一的，不存在多例互相独立的情况，只要使用了本类，哪怕不是一个对象，多是共享着同一套缓存。
 * 
 * @since 1.0.0
 * @author Ghwolf
 *
 */
public class ThreadLocalCookieStore implements CookieStore,Serializable{
	private static final long serialVersionUID = 1072498811474018446L;
	/**
	 * 缓存cookie
	 */
	private static final ThreadLocal<List<Cookie>> cookieThreadLocal = new ThreadLocal<>();
	/**
	 * 是否要进行cookie缓存，默认不会进行任何cookie缓存
	 */
	private static final ThreadLocal<Boolean> doCacheFlag = new ThreadLocal<>();
	
	private static final ThreadLocalCookieStore instance = new ThreadLocalCookieStore();
	
	private ThreadLocalCookieStore(){
	}
	
	/**
	 * 获取本类实例
	 * @return 本类实例化对象
	 */
	public static ThreadLocalCookieStore getInstance() {
		return instance;
	}
	
	/**
	 * 设置对cookie进行缓存。当前线程在后续的所有操作均会对cookie进行缓存处理。默认是不会的。
	 */
	public static void doCacheable() {
		doCacheFlag.set(Boolean.TRUE);
	}
	
	/**
	 * 禁止cookie缓存，设置之后，会删除当前存储的所有cookie，同时后续操作也不会再存储cookie。
	 */
	public static void doNotCacheable() {
		cookieThreadLocal.remove();
		doCacheFlag.remove();
	}
	
	
	
	private List<Cookie> getLocal() {
		List<Cookie> list = cookieThreadLocal.get();
		if (list == null) {
			list = new ArrayList<>();
			cookieThreadLocal.set(list);
		}
		return list ;
	}
	
	private boolean cacheable() {
		return Boolean.TRUE.equals(doCacheFlag.get());
	}
	
	@Override
	public void addCookie(Cookie cookie) {
		if (cookie != null && cacheable()) {
			List<Cookie> cookies = getLocal();
			cookies.remove(cookie);
			if (!cookie.isExpired(new Date())) {
				cookies.add(cookie);
			}
		}
	}

	@Override
	public List<Cookie> getCookies() {
		List<Cookie> cookies = cookieThreadLocal.get();
		return cookies == null ? Collections.emptyList() : Collections.unmodifiableList(cookies);
	}

	@Override
	public boolean clearExpired(Date date) {
		if (date == null) {
            return false;
        }
        List<Cookie> cookies = cookieThreadLocal.get();
        if (cookies == null || cookies.isEmpty()) {
        	return false ; 
        }
        
        Iterator<Cookie> it = cookies.iterator(); 
        boolean removed = false;
        while(it.hasNext()) {
        	if (it.next().isExpired(date)) {
        		it.remove();
        		removed = true;
        	}
        }
        return removed ;
	}

	@Override
	public void clear() {
		cookieThreadLocal.remove();
	}


    @Override
    public String toString() {
		List<Cookie> cookies = cookieThreadLocal.get();
		return cookies == null ? Collections.emptyList().toString() : cookies.toString();
    }
}
